#!/usr/bin/python
# -*- coding: utf-8 -*-
import re
from person import person
from yapgvb import *

class stats:
    def __init__(self, nickfile = 'nimet.conf'):
        """
            nickfile includes list of alter egos for every nick on a format:
                nick1 nick1_alt1 nick1_alt2
                nick2
                nick3 nick3_alt
                ...
        """
        # Open the logfile. This should not be given here but from command line
        self.a       = open("/home/micko/delta.log", 'r')
        self.doubles = self.getnicks(nickfile)
        #print self.doubles # debug message
        self.people  = dict()


    def start(self):
        """
            Rename this function
            Reads the log and passes lines to getNickRef function
            If it finds a reference, it passes it to addRef function
        """
        for line in self.a:
            temp = self.getNickRef(line)
            if temp == -1:
                pass
            else:
                self.addRef(temp[0], temp[1]) 

    def getnicks(self, nickfile):
        """
            Reads the nickfile and returns a list containing them
        """
        temp = dict()
        nfile = open(nickfile, 'r')
        for i in nfile:
            lista = i.rsplit()
            temp[lista.pop(0)] = lista
        return temp

    def getNickRef(self, line):
        """
            This function examines the string it recieves and tries to decide whether
            it contains a message from person to another. Basically it reacts to something
            like this:
                < nick1> nick2: Hi!
            Fist nick1 in <>:s and then nick2 followed by a colon 
            Returns (nick,ref) tuple or -1 if fails
        
        """
        merkki1 = line.find("<") + 1
        merkki2 = line.find(">")
        # I have absolutely no idea about the next line. Probably it has something
        # to do with merkki3 being set before reading it... Maybe I need some try-except
        merkki3 = "a"
               
        colon = re.compile(": ").search(line)
        
        if colon != None:
            merkki3 = colon.start()
        else:
            return -1
            
        nick    = line[merkki1:merkki2].strip("@+ ")
        
        ref     = line[(merkki2 + 2):merkki3]
        if re.compile("\s").search(ref) == None:
            return (nick, ref)
        else:
            return -1
    
    def addRef(self, nick, ref):
        """
            Gets nick and ref and adds them to the messages-dict in
            people-dict
        """
        if self.people.has_key(nick):
            if self.people[nick].has_key(ref):
                self.people[nick][ref] += 1
            else:
                self.people[nick][ref] = 1
        else:
            self.people[nick] = dict()
            self.people[nick][ref] = 1
    
    def olioi(self):
        """
            Creates person-objects from the people dict. Why am I doing it this hard...
            The whole people dict could be removed and do this right away.
            
            Something horrible is going on inside the second for-loop
        """
        taulu  = dict()
        taulu2 = dict()
        for i in self.people:
            if i in self.doubles:
                taulu[i] = person(i, self.people[i], ae = self.doubles[i])
            else:
                taulu[i] = person(i, self.people[i])
        print taulu
        
        for i in taulu:
            if i in taulu2:
                continue
            elif i in self.doubles:
                if i in taulu:
                    taulu2[i] = taulu[i]
                continue
                
            elif i not in self.doubles:
                for j in self.doubles:
                    if self.doubles[j] != None:
                        if i in self.doubles[j]:
                            if j not in taulu2:
                                if j in taulu:
                                    taulu2[j] = taulu[j]
                                else:
                                    taulu2[j] = taulu[i]
                                    taulu2[j].nimi = j
                                    
                                break 
                            else:
                                taulu2[j].add(taulu[i])
                                break
                else:
                    if i in taulu:
                        taulu2[i] = taulu[i]
                continue
        # replace the people dict with a dict including the people objects
        # this is dirty...
        self.people = taulu2.copy()
    
    def clean1(self):
        """
            This fuction... I have no clue. To me it looks like it doesn't do anything on the
            people dict and doesn't return anything.
            
            I really don't remember what this is for
        """
        nickit = list()
        people2 = dict()
        for i in self.people:
            nickit.append(i)
        
        for i in self.people:
            people2[i] = dict(self.people[i])
            for j in self.people[i]:
                try:
                    if nickit.index(j) == -1:
                        people2[i][j] = dict(self.people[i][j])
                except ValueError:
                    del people2[i][j]

    def remove_doubles(self):
        """
            Sums the alter egos inside same dict
            nick1{'nick2': 10, 'nick2_alt': 2,...}
            ->
            nick1{'nick2': 12,...}
        """
        removable = dict()
        for lista in self.people:
            for nick1 in self.people[lista].messages:
                for nick2 in self.people[lista].messages:
                    if (nick2 in self.doubles) & (nick2 in self.people):
                        if nick1 in self.people[nick2].ae:
                            self.people[lista].messages[nick2] =+ self.people[lista].messages[nick1]
                            removable[lista] = nick1
                            
        for i in removable:
            #print self.people[i].nimi, self.people[i].messages[removable[i]]
            del self.people[i].messages[removable[i]]

        
    def clean2(self):
        """
            Sums the alter ego persons
        """
        
        for eka in self.people:
            for toka in self.people:
                if toka in self.people[eka].messages:
                    if eka in self.people[toka].messages:
                        self.people[toka].messages[eka] += self.people[eka].messages[toka]
                        self.people[eka].messages[toka]  = self.people[toka].messages[eka]
                    else:
                        self.people[toka].messages[eka]  = self.people[eka].messages[toka]    
                else:
                    if eka in self.people[toka].messages:
                        self.people[eka].messages[toka]  = self.people[toka].messages[eka]

    def clean3(self):
        """
            If there are references for which there are no persons,
            they will be removed.
            
            The function getNickRef considers everything between the first > and :
            to be a nick. e.g.
            < micko> hey look at this link: http://...
            would return nick,ref tuple ('micko', 'hey look at this link')
            
            This function removes everything like that.
        """
        for i in self.people:
            temp = list()
            for j in self.people[i].messages:
                if j not in self.people:
                    temp.append(j)

            for k in temp:
                del self.people[i].messages[k]

    def removesmall(self, n):
        """
            Calculates the average messages between persons i and j
            and removes everyhing below n times that number
            More the nicks on channel bigger the n should be in
            order to get a clean graph
        """
        
        ka = 0
        laskuri = 0
        
        for i in self.people:
            for j in self.people[i].messages:
                ka = ka + self.people[i].messages[j]
                laskuri = laskuri + 1
        
        alaraja = ka/laskuri*n
        poistettavat = dict()
        
        for i in self.people:
            for j in self.people[i].messages:
                print i, j, self.people[i].messages[j]
                if self.people[i].messages[j] < alaraja:
                    print "pois"
                    if i not in poistettavat:
                        poistettavat[i] = list()
                    poistettavat[i].append(j)
                    
        
        print poistettavat
        for i in poistettavat:
            #print i, poistettavat[i]
            for j in poistettavat[i]:
                del self.people[i].messages[j]
            #del self.people[poistettavat[i]].messages[i]


    def graafita(self):
        """
            Makes self.people into a graafin
        """
        
        self.graafi = Graph(name_or_open_file = 'Irssistatsi')
        nodet = dict()
        edget = dict()
#        for i in self.people:
#            nodet[i] =  self.graafi.add_node(i, label = i)
            
        for i in self.people:
            for j in self.people[i].messages:
                
                if i not in nodet:
                    nodet[i] =  self.graafi.add_node(i, label = i)
                if j not in nodet:
                    nodet[j] =  self.graafi.add_node(j, label = j)
                    
                if (j + " " + i) not in edget:
                    edget[i + " " + j] = nodet[i] - nodet[j]
                
        self.graafi.layout('dot')
        self.graafi.render(outstream='testi.png',format='png')

                
# I know... Not like this.
# Some day I'll make a main program which calls these... Also some of these
# can be combined etc...

statsi = stats()
statsi.start() 
statsi.clean1()
statsi.olioi()
statsi.clean2()
statsi.remove_doubles()
statsi.clean3()
statsi.removesmall(16)

# Debug:
#for i in statsi.people:
#    a = statsi.people[i].messages.keys()
#    a.sort()
#    print i, statsi.people[i].messages
    
statsi.graafita()
print "valmis"
    

